using System;
using System.Collections.Generic;
using System.Text;

//Java namespace
using ikvm.io;
//Pellet namespaces
using org.mindswap;
using org.mindswap.pellet;
//using org.mindswap.pellet.jena.PelletReasonerFactory;
using org.mindswap.pellet.jena;
//Jena namespaces
using com.hp.hpl.jena.ontology;
using com.hp.hpl;
using com.hp.hpl.jena.rdf.model;
using com.hp.hpl.jena.reasoner;
using com.hp.hpl.jena.util.iterator;
using com.hp.hpl.jena.query;

namespace Geoconcepts.SemanticServices
{
    /// <summary>
    /// Class to use available Reasoners (Jena, Pellet) inference support.
    /// </summary
    public class Reasoner
    {
        #region Public Variables
        #endregion Public Variables

        #region Private Variables
        private OntModel modelTBox = null;
        private OntModel modelABox = null;
        private OntModel modelSpecified = null;
        #endregion Private Variables

        #region Constructor
        /// <summary>
        /// Creates a new Reasoner instance with empty TBox, ABox and Mixed models
        /// </summary>
        public Reasoner()
        {
            InicializeOptions();
            modelTBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
            modelABox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
            modelSpecified = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
        }

        /// <summary>
        /// Creates a new Reasoner with an empty ABox and a TBox using the ontology retrieved from strTBoxURL
        /// It also creates a Mixed model = TBox + ABox that can be used for inferencing
        /// </summary>
        /// <param name="strTBoxURL">Full URI of the ontology</param>
        public Reasoner(string strTBoxURL)
        {
            InicializeOptions();
            modelTBox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
            modelABox = ModelFactory.createOntologyModel(PelletReasonerFactory.THE_SPEC);
            
            // Create modelSpecified using as TBox the ontology provided by strTBoxURL
            modelTBox.read(strTBoxURL);

            com.hp.hpl.jena.reasoner.Reasoner pelletReasoner = PelletReasonerFactory.theInstance().create();
            pelletReasoner = pelletReasoner.bindSchema(modelTBox);

            OntModelSpec specModel = new OntModelSpec(PelletReasonerFactory.THE_SPEC);
            specModel.setReasoner(pelletReasoner);

            modelSpecified = ModelFactory.createOntologyModel(specModel, modelABox);
        }
        #endregion

        #region Ontology Population
        /// <summary>
        /// Adds a new Individual to the ABox
        /// </summary>
        /// <param name="strClassNamespace">URI Namespace of the class</param>
        /// <param name="strClassName">Class name</param>
        /// <param name="strIndividualNamespace">URI Namespace of the Individual</param>
        /// <param name="strIndividualName">Name for the Individual</param>
        public void AddIndividual(string strClassNamespace,string strClassName,string strIndividualNamespace,string strIndividualName)
        {
            try
            {
                Resource rClass = modelSpecified.getResource(strClassNamespace + strClassName);
                // com.hp.hpl.jena.ontology.Individual iIndividual  // If access to Individual object needed
                modelABox.createIndividual(strIndividualNamespace + strIndividualName, rClass);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Adds a new property triple to the ABox
        /// </summary>
        /// <param name="strSubNamespace">Namespace of subject</param>
        /// <param name="strSubIndividualName">Name of subject Individual</param>
        /// <param name="strPropNamespace">Namespace of property</param>
        /// <param name="strPropClassName">Class name of property</param>
        /// <param name="strObjNamespace">Namespace of object</param>
        /// <param name="strObjIndividualName">Name of object Individual</param>
        public void AddProperty(string strSubNamespace, string strSubIndividualName, string strPropNamespace, string strPropClassName, string strObjNamespace, string strObjIndividualName)
        {
            try
            {
                com.hp.hpl.jena.ontology.Individual iSubIndividual = modelABox.getIndividual(strSubNamespace + strSubIndividualName);
                com.hp.hpl.jena.ontology.Individual iObjIndividual = modelABox.getIndividual(strObjNamespace + strObjIndividualName);

                Property pClass = modelSpecified.getProperty(strPropNamespace + strPropClassName);
                iSubIndividual.addProperty(pClass, iObjIndividual);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Adds a new Datatype property triple to the ABox
        /// </summary>
        /// <param name="strSubNamespace">Namespace of subject</param>
        /// <param name="strSubIndividualName">Name of subject Individual</param>
        /// <param name="strPropNamespace">Namespace of property</param>
        /// <param name="strPropClassName">Class name of property</param>
        /// <param name="strObjDatatype">Datatype value</param>
        public void AddDataTypeProperty(string strSubNamespace, string strSubIndividualName, string strPropNamespace, string strPropClassName, string strObjDatatype)
        {
            try
            {
                com.hp.hpl.jena.ontology.Individual iSubIndividual = modelABox.getIndividual(strSubNamespace + strSubIndividualName);
                Property pClass = modelSpecified.getProperty(strPropNamespace + strPropClassName);
                iSubIndividual.addProperty(pClass, modelSpecified.createTypedLiteral(strObjDatatype));
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }


        #endregion Ontology Population

        #region Inferencing
        public byte[] ReturnInferencedGraph()
        {
            byte[] owlFile;
            try
            {
                java.io.ByteArrayOutputStream ostrABox = new java.io.ByteArrayOutputStream();

                #region Prefijos de espacios de nombres
                //modelABox.setNsPrefix("gml",strGMLNameSpace);
                //modelABox.setNsPrefix("gc", strGCNameSpace);
                #endregion Prefijos de espacios de nombres

                #region Guardar ABox con inferencias Tests
                //modelABox.prepare();
                //((PelletInfGraph)modelABox.getGraph()).classify();
                //bool isPrepared = ((PelletInfGraph)modelABox.getGraph()).isPrepared();
                //modelABox.writeAll(ostrABox, null, null);
                // Guardar con inferencias
                //modelABox.write(ostrABox);

                //((PelletInfGraph) model.getGraph()).getKB().classify();
                //((PelletInfGraph) model.getGraph()).getKB().realize();

                //owlFile = ostrABox.toByteArray();
                #endregion Guardar ABox con inferencias Tests

                // Probamos con el modelo "arrejuntau"
                modelSpecified.prepare();
                modelSpecified.writeAll(ostrABox, null, null);
                owlFile = ostrABox.toByteArray();
                return owlFile;
            }
            catch (Exception ex)
            {
                throw ex;
            }




        }
        #endregion Inferencing

        #region Reasoner Configuration
        /// <summary>
        /// Inicialite Pellet reasoner options and set proxy settings if needed
        /// </summary>
        private void InicializeOptions()
        {
            PelletOptions.USE_COMPLETION_QUEUE = true;
            PelletOptions.USE_SMART_RESTORE = false;
            PelletOptions.USE_CONTINUOUS_RULES = true;
            PelletOptions.DL_SAFE_RULES = true;

            // Initialize network options
            NetworkSettings.SetProxySettings();
        }
        #endregion Reasoner Configuration
    }
}
